package es

import (
	"context"
	"strings"
	"gopkg.in/olivere/elastic.v5"
)

// es model
type Model struct {
	indexName  []string
	client     *EsClient
	query	   *Query
	fields     []string
}

// 不允许外部调用，仅允许 client.Index(xxx, xxx) 返回
func newModel(indexName string, client *EsClient) *Model {
	indexNames := []string{}
	for _, n := range strings.Split(indexName, ",") {
		indexNames = append(indexNames, strings.Trim(n, " "))
	}
	query := newQuery()
	// 返回index
	return &Model{
		indexName:  indexNames,
		client:     client,
		query:      query,
	}
}

// 设置索引类型
func (m *Model) SetIndex(indexNames ...string) {
	m.indexName = indexNames
}

// 获取对应index的query
func (m *Model) Query() *Query {
	return newQuery()
}

// 获取所有记录
func (m *Model) All() (result []interface{}, total int64, err error) {
	return m.GetList()
}

// 获取单条记录
func (m *Model) One() (result interface{}, err error) {
	return m.GetFirst()
}

// 保存文档
func (m *Model) Save(id string, doc interface{}) (err error) {
	client := m.client.rawClient
	ctx := context.Background()
	_, err = client.Index().Index(m.indexName[0]).Id(id).BodyJson(doc).Do(ctx)
	return
}

// 获取文档
func (m *Model) Find(id string) (doc interface{}, err error) {
	client := m.client.rawClient
	ctx := context.Background()
	res, e := client.Get().Index(m.indexName[0]).Id(id).Do(ctx)
	if e != nil && e.Error() == "elastic: Error 404 (Not Found)" {
		return nil, nil
	} else if e != nil {
		return nil, err
	}
	return res, nil
}

// 批量更新
func (m *Model) Update(params map[string]interface{}) (res interface{},err error) {
	if len(params) == 0 {
		return nil, nil
	}
	client := m.client.rawClient
	query := client.UpdateByQuery().Index(m.indexName[0]).Query(m.getBoolQuery()).From(m.query.from).Size(m.query.size)
	var script string
	for k, _ := range params {
		script += "ctx._source." + k + "=params." + k + ";"
	}
	script = script[:len(script)-1]
	_, err = query.Script(elastic.NewScript(script).Params(params)).Do(context.Background())
	return
}

// 更新指定id文档
func (m *Model) UpdateById(id string, updates map[string]interface{}) (err error) {
	client := m.client.rawClient
	_, err = client.Update().Index(m.indexName[0]).Id(id).Doc(updates).Do(context.Background())
	return
}

// 批量删除
func (m *Model) Delete() (res interface{}, err error) {
	rawClient := m.client.rawClient
	query := rawClient.DeleteByQuery().Index(m.indexName[0]).Query(m.getBoolQuery()).From(m.query.from).Size(m.query.size)
	res, err = query.Do(context.Background())
	return
}

// 删除指定id文档
func (m *Model) DeleteById(id string) (res interface{}, err error) {
	rawClient := m.client.rawClient
	res, err = rawClient.Delete().Index(m.indexName[0]).Id(id).Do(context.Background())
	return
}

// 增量
func (m *Model) Increment(column string, number float64) (res interface{}, err error) {
	client := m.client.rawClient
	query := client.UpdateByQuery().Index(m.indexName[0]).Query(m.getBoolQuery()).From(m.query.from).Size(m.query.size)
	_, err = query.Script(elastic.NewScript("ctx._source." + column + " += params." + column).Params(map[string]interface{}{column: number})).Do(context.Background())
	return
}

// 减量
func (m *Model) Decrement(column string, number float64) (res interface{}, err error) {
	client := m.client.rawClient
	query := client.UpdateByQuery().Index(m.indexName[0]).Query(m.getBoolQuery()).From(m.query.from).Size(m.query.size)
	_, err = query.Script(elastic.NewScript("ctx._source." + column + " -= params." + column).Params(map[string]interface{}{column: number})).Do(context.Background())
	return
}

// 是否存在
func (m *Model) Exists(id string) (res interface{}, err error) {
	return m.client.rawClient.Exists().Index(m.indexName[0]).Id(id).Do(context.TODO())
}

// 获取es错误信息
func GetError(err error) *elastic.Error {
	return err.(*elastic.Error)
}